package com.szcinda.service.dto.consolidate;

import com.szcinda.controller.Result;
import com.szcinda.repository.*;
import com.szcinda.service.PageResult;
import com.szcinda.service.SnowFlakeFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class ConsolidateServiceImpl implements ConsolidateService {
    private final ConsolidateRepository consolidateRepository;
    private final SnowFlakeFactory snowFlakeFactory = SnowFlakeFactory.getInstance();
    private final GhOrderRepository ghOrderRepository;

    public ConsolidateServiceImpl(ConsolidateRepository consolidateRepository, GhOrderRepository ghOrderRepository) {
        this.consolidateRepository = consolidateRepository;
        this.ghOrderRepository = ghOrderRepository;
    }

    @Override
    public List<String> importData(List<ConsolidateImportDto> importDtoList) {
        List<String> messages = new ArrayList<>();
        for (ConsolidateImportDto consolidateImportDto : importDtoList) {
            Consolidate record = consolidateRepository.findByJcNo(consolidateImportDto.getJcNo());
            if (record != null) {
                // 判断是否封账
                GhOrder ghOrder = ghOrderRepository.findByOrderNumber(consolidateImportDto.getOrderNo());
                if (ghOrder != null) {
                    if (ghOrder.getSettlement().equals(BillType.STATUS_YJS) || ghOrder.getOutSettlement().equals(BillType.STATUS_YJS)) {
                        messages.add(String.format("订单编号【%s】已经封账，不能修改", consolidateImportDto.getOrderNo()));
                    } else {
                        BeanUtils.copyProperties(consolidateImportDto, record, "id");
                    }
                }
            } else {
                record = new Consolidate();
                BeanUtils.copyProperties(consolidateImportDto, record);
                record.setId(snowFlakeFactory.nextId("CD"));
            }
            consolidateRepository.saveAndFlush(record);
        }
        return messages;
    }

    @Override
    public PageResult<Consolidate> query(ConsolidateQueryDto params) {
        Specification<Consolidate> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (!StringUtils.isEmpty(params.getJcNo())) {
                Predicate jcNo = criteriaBuilder.like(root.get("jcNo"), "%" + params.getJcNo().trim() + "%");
                predicates.add(jcNo);
            }
            if (!StringUtils.isEmpty(params.getPNo())) {
                Predicate pNo = criteriaBuilder.like(root.get("pNo"), "%" + params.getPNo().trim() + "%");
                predicates.add(pNo);
            }
            if (!StringUtils.isEmpty(params.getOrderNo())) {
                Predicate pNo = criteriaBuilder.like(root.get("orderNo"), "%" + params.getOrderNo().trim() + "%");
                predicates.add(pNo);
            }
            if (!StringUtils.isEmpty(params.getPackageNo())) {
                Predicate packageNo = criteriaBuilder.like(root.get("packageNo"), "%" + params.getPackageNo().trim() + "%");
                predicates.add(packageNo);
            }
            if (!StringUtils.isEmpty(params.getPackageTime())) {
                Predicate packageTime = criteriaBuilder.like(root.get("packageTime"), "%" + params.getPackageTime().trim() + "%");
                predicates.add(packageTime);
            }
            if (!StringUtils.isEmpty(params.getBelong())) {
                Predicate belong = criteriaBuilder.equal(root.get("belong"), params.getBelong().trim());
                predicates.add(belong);
            }
            if (params.getCreateTimeStart() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), params.getCreateTimeStart().atStartOfDay());
                predicates.add(timeStart);
            }
            if (params.getCreateTimeEnd() != null) {
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("createTime"), params.getCreateTimeEnd().plusDays(1).atStartOfDay());
                predicates.add(timeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        Pageable pageable = new PageRequest(params.getPage() - 1, params.getPageSize(), sort);
        Page<Consolidate> details = consolidateRepository.findAll(specification, pageable);
        List<String> orderNos = details.getContent().stream().filter(consolidate -> StringUtils.hasText(consolidate.getOrderNo())).map(Consolidate::getOrderNo).collect(Collectors.toList());
        List<GhOrder> ghOrders = ghOrderRepository.findByOrderNumberIn(orderNos);
        for (Consolidate consolidate : details.getContent()) {
            ghOrders.stream().filter(ghOrder -> ghOrder.getOrderNumber().equals(consolidate.getOrderNo()))
                    .findFirst()
                    .ifPresent(ghOrder -> {
                        if (ghOrder.getSettlement().equals(BillType.STATUS_YJS) || ghOrder.getOutSettlement().equals(BillType.STATUS_YJS)) {
                            consolidate.setOrderLock(true);
                        }
                    });
        }
        return PageResult.of(details.getContent(), params.getPage(), params.getPageSize(), details.getTotalElements());
    }

    @Override
    public List<Consolidate> queryAll(ConsolidateQueryDto params) {
        Specification<Consolidate> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (!StringUtils.isEmpty(params.getJcNo())) {
                Predicate jcNo = criteriaBuilder.like(root.get("jcNo"), "%" + params.getJcNo().trim() + "%");
                predicates.add(jcNo);
            }
            if (!StringUtils.isEmpty(params.getPNo())) {
                Predicate pNo = criteriaBuilder.like(root.get("pNo"), "%" + params.getPNo().trim() + "%");
                predicates.add(pNo);
            }
            if (!StringUtils.isEmpty(params.getPackageNo())) {
                Predicate packageNo = criteriaBuilder.like(root.get("packageNo"), "%" + params.getPackageNo().trim() + "%");
                predicates.add(packageNo);
            }
            if (!StringUtils.isEmpty(params.getPackageTime())) {
                Predicate packageTime = criteriaBuilder.like(root.get("packageTime"), "%" + params.getPackageTime().trim() + "%");
                predicates.add(packageTime);
            }
            if (!StringUtils.isEmpty(params.getBelong())) {
                Predicate belong = criteriaBuilder.equal(root.get("belong"), params.getBelong().trim());
                predicates.add(belong);
            }
            if (params.getCreateTimeStart() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), params.getCreateTimeStart().atStartOfDay());
                predicates.add(timeStart);
            }
            if (params.getCreateTimeEnd() != null) {
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("createTime"), params.getCreateTimeEnd().plusDays(1).atStartOfDay());
                predicates.add(timeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        return consolidateRepository.findAll(specification);
    }

    @Override
    public List<Consolidate> queryByIds(List<String> ids) {
        return consolidateRepository.findAll(ids);
    }

    @Override
    public void delete(String id) {
        consolidateRepository.delete(id);
    }

    @Override
    public Result<String> update(Consolidate update) {
        Consolidate consolidate = consolidateRepository.findOne(update.getId());
        // 判断是否封账
        GhOrder ghOrder = ghOrderRepository.findByOrderNumber(consolidate.getOrderNo());
        if (ghOrder != null) {
            if (ghOrder.getSettlement().equals(BillType.STATUS_YJS) || ghOrder.getOutSettlement().equals(BillType.STATUS_YJS)) {
                return Result.fail("该拼箱订单对应的订单编号已封账，不能修改");
            }
        }
        BeanUtils.copyProperties(update, consolidate, "id");
        consolidateRepository.save(consolidate);
        return Result.success();
    }
}
